
package me.liuhui.mall.manager.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import me.liuhui.mall.common.base.vo.ResultVO;
import me.liuhui.mall.manager.cache.RedisCache;
import me.liuhui.mall.manager.runtime.AdminSessionHolder;
import me.liuhui.mall.manager.service.AdminService;
import me.liuhui.mall.manager.service.PermissionService;
import me.liuhui.mall.manager.service.convertor.AdminConverter;
import me.liuhui.mall.manager.service.convertor.AdminLoginRecordConverter;
import me.liuhui.mall.manager.service.dto.admin.*;
import me.liuhui.mall.manager.service.vo.admin.*;
import me.liuhui.mall.manager.utils.CacheConstants;
import me.liuhui.mall.repository.mapper.*;
import me.liuhui.mall.repository.model.Admin;
import me.liuhui.mall.repository.model.AdminLoginRecord;
import me.liuhui.mall.repository.model.AdminRole;
import me.liuhui.mall.repository.model.Permission;
import me.liuhui.mall.repository.model.dao.AdminRoleDTO;
import me.liuhui.mall.repository.model.enums.AdminStatus;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created on 2020/10/14 20:12
 * <p>
 * Description: [TODO]
 * <p>
 *
 * @author [清远]
 */
@Service
public class AdminServiceImpl implements AdminService {
    @Value("${mall.file.domain}")
    private String frontDomain;
    @Resource
    private AdminLoginRecordConverter adminLoginRecordConverter;
    @Resource
    private AdminLoginRecordMapper adminLoginRecordMapper;
    @Resource
    private AdminConverter adminConverter;
    @Resource
    private AdminMapper adminMapper;
    @Resource
    private AdminRoleMapper adminRoleMapper;
    @Resource
    private PermissionService permissionService;
    @Resource
    private UserMapper userMapper;
    @Resource
    private ProductMapper productMapper;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private SessionTokenMapper sessionTokenMapper;

    @Resource
    private RedisCache redisCache;

    @Override
    public ResultVO<AdminInitVO> init() {
        ResultVO<List<PermissionVO>> setResultVO = permissionService.menuTree();
        AdminInitVO adminInitVO = new AdminInitVO();
        adminInitVO.setMenuInfo(setResultVO.getData());
        adminInitVO.setRealName(AdminSessionHolder.getCurrentAdmin().getRealName());
        Set<String> perCodes = AdminSessionHolder.getPermission().stream().map(Permission::getCode).collect(Collectors.toSet());
        adminInitVO.setPerCodes(perCodes);
        adminInitVO.setFrontDomain(frontDomain);
        return ResultVO.success(adminInitVO);
    }

    @Override
    public ResultVO<AdminVO> myInfo() {
        Long adminId = AdminSessionHolder.getCurrentAdmin().getAdminId();
        Admin admin = adminMapper.selectById(adminId);
        return ResultVO.success(adminConverter.toVo(admin));
    }

    @Override
    public ResultVO<Boolean> modifyMyInfo(AdminDTO dto) {
        dto.setId(AdminSessionHolder.getCurrentAdmin().getAdminId());
        Admin admin = adminConverter.toEntity(dto);
        adminMapper.updateById(admin);
        return ResultVO.success();
    }

    @Override
    public ResultVO<Boolean> modifyMyPassword(ModifyMyPasswordDTO dto) {
        if (!Objects.equals(dto.getPassword(), dto.getConfirmPassword())) {
            return ResultVO.buildFailResult("两次密码不一致！");
        }
        Long adminId = AdminSessionHolder.getCurrentAdmin().getAdminId();
        Admin admin = adminMapper.selectById(adminId);
        if (!Objects.equals(admin.getPassword(), DigestUtils.md5DigestAsHex(dto.getOldPassword().getBytes()))) {
            return ResultVO.buildFailResult("原密码错误！");
        }
        admin.setPassword(DigestUtils.md5DigestAsHex(dto.getPassword().getBytes()));
        adminMapper.updateById(admin);
        return ResultVO.success();
    }


    @Override
    public ResultVO<Boolean> changeStatus(ChangeStatusDTO dto) {
        Admin admin = adminMapper.selectById(dto.getId());
        if (admin == null) {
            return ResultVO.buildFailResult("管理员不存在");
        }
        if (!Objects.equals(admin.getStatus(), dto.getStatus())) {
            admin.setStatus(dto.getStatus());
            adminMapper.updateById(admin);
        }
        return ResultVO.success();
    }

    @Override
    public ResultVO<ListAdminLoginRecordVO> listLoginRecored(ListAdminLoginRecordDTO dto) {
        LambdaQueryWrapper<AdminLoginRecord> wrapper = Wrappers.lambdaQuery();
        wrapper.lt(Objects.nonNull(dto.getMaxCreateTime()), AdminLoginRecord::getCreateTime, dto.getMaxCreateTime())
                .gt(Objects.nonNull(dto.getMinCreateTime()), AdminLoginRecord::getCreateTime, dto.getMinCreateTime())
                .eq(Objects.nonNull(dto.getAdminId()), AdminLoginRecord::getAdminId, dto.getAdminId())
                .eq(StrUtil.isNotBlank(dto.getAdminUserName()), AdminLoginRecord::getAdminUserName, dto.getAdminUserName());
        Page<AdminLoginRecord> page = new Page<>(dto.getPage(), dto.getLimit());
        Page<AdminLoginRecord> adminLoginRecords = adminLoginRecordMapper.selectPage(page, wrapper);
        ListAdminLoginRecordVO vo = new ListAdminLoginRecordVO();
        vo.setTotal(adminLoginRecords.getTotal());
        vo.setList(adminLoginRecordConverter.toVo(adminLoginRecords.getRecords()));
        return ResultVO.success(vo);
    }

    @Override
    public ResultVO<WelcomeVO> welcome() {
        WelcomeVO vo = new WelcomeVO();
        vo.setUserNum(userMapper.selectCount(null));
        vo.setProductNum(productMapper.selectCount(null));
        vo.setOrderNum(orderMapper.selectCount(null));
        vo.setOrderAmount(orderMapper.sumAmount(null));
        Date minDate = Date.from(LocalDateTime.now().minusMonths(1).atZone(ZoneId.systemDefault()).toInstant());
        vo.setLoginCount(sessionTokenMapper.countToken(minDate, null));
        vo.setOrderCount(orderMapper.countOrder(minDate, null));
        return ResultVO.success(vo);
    }


    @Override
    public ResultVO<ListAdminVO> list(ListAdminDTO dto) {
        LambdaQueryWrapper<Admin> wrapper = Wrappers.lambdaQuery();
        wrapper.lt(Objects.nonNull(dto.getMaxCreateTime()), Admin::getCreateTime, dto.getMaxCreateTime())
                .gt(Objects.nonNull(dto.getMinCreateTime()), Admin::getCreateTime, dto.getMinCreateTime())
                .lt(Objects.nonNull(dto.getMaxLastLoginTime()), Admin::getLastLoginTime, dto.getMaxLastLoginTime())
                .gt(Objects.nonNull(dto.getMinLastLoginTime()), Admin::getLastLoginTime, dto.getMinLastLoginTime())
                .eq(StrUtil.isNotBlank(dto.getRealName()), Admin::getRealName, dto.getRealName())
                .eq(StrUtil.isNotBlank(dto.getUsername()), Admin::getUsername, dto.getUsername())
                .eq(Objects.nonNull(dto.getStatus()), Admin::getStatus, dto.getStatus());
        Page<Admin> page = new Page<>(dto.getPage(), dto.getLimit());
        Page<Admin> adminPage = adminMapper.selectPage(page, wrapper);
        List<Long> adminIds = adminPage.getRecords().stream().map(Admin::getId).collect(Collectors.toList());
        List<AdminRoleDTO> adminRoles = adminRoleMapper.selectRoleByAdmin(adminIds);

        Map<Long, AdminRoleDTO> adminRoleMap = adminRoles.stream().collect(Collectors.toMap(AdminRoleDTO::getAdminId, adminRole -> adminRole, (k1, k2) -> k1));
        List<AdminVO> adminVos = adminConverter.toVo(adminPage.getRecords());
        for (AdminVO adminVO : adminVos) {
            AdminRoleDTO adminRoleDTO = adminRoleMap.get(adminVO.getId());
            if (adminRoleDTO != null) {
                adminVO.setRoles(adminRoleDTO.getRoles());
            }
        }
        ListAdminVO vo = new ListAdminVO();
        vo.setList(adminVos);
        vo.setTotal(adminPage.getTotal());
        return ResultVO.success(vo);
    }

    @Override
    public ResultVO<Boolean> create(AdminDTO dto) {
        Map<String, Object> cond = new HashMap<>(2);
        cond.put("username", dto.getUsername());
        LambdaQueryWrapper<Admin> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(Admin::getUsername, dto.getUsername());
        long count = adminMapper.selectCount(wrapper);
        if (count > 0) {
            return ResultVO.buildFailResult("用户名已存在！");
        }
        Admin entity = adminConverter.toEntity(dto);
        entity.setCreateTime(new Date());
        entity.setPassword(DigestUtils.md5DigestAsHex(dto.getPassword().getBytes()));
        entity.setStatus(AdminStatus.NORMAL.getCode());
        entity.setCreateAdmin(AdminSessionHolder.getCurrentAdmin().getUsername());
        adminMapper.insert(entity);
        for (String roleId : dto.getRoleIds().split(",")) {
            AdminRole adminRole = new AdminRole();
            adminRole.setRoleId(Long.valueOf(roleId));
            adminRole.setAdminId(entity.getId());
            adminRoleMapper.insert(adminRole);
        }
        return ResultVO.success();
    }

    @Override
    public ResultVO<Boolean> modify(AdminDTO dto) {
        Admin admin = adminMapper.selectById(dto.getId());
        if (admin == null) {
            return ResultVO.buildFailResult("管理员不存在");
        }
        Admin entity = adminConverter.toEntity(dto);
        if (StrUtil.isNotBlank(dto.getPassword())) {
            entity.setPassword(DigestUtils.md5DigestAsHex(dto.getPassword().getBytes()));
        } else {
            entity.setPassword(null);
        }
        adminMapper.updateById(entity);
        adminRoleMapper.deleteByAdmin(dto.getId());
        for (String roleId : dto.getRoleIds().split(",")) {
            AdminRole adminRole = new AdminRole();
            adminRole.setRoleId(Long.valueOf(roleId));
            adminRole.setAdminId(dto.getId());
            adminRoleMapper.insert(adminRole);
        }
        redisCache.delete(CacheConstants.ADMIN_PERMISSION_KEY + dto.getId());
        return ResultVO.success();
    }

    @Override
    public ResultVO<Boolean> delete(Set<Long> ids) {
        for (Long id : ids) {
            adminMapper.deleteById(id);
        }
        return ResultVO.success();
    }

}
